﻿/*
 * ©2009-2010 XELF
 * http://xelf.info
 */

namespace XELF.Framework {

	/// <summary>
	/// 平面
	/// </summary>
	public partial struct Plane {
		/// <summary>
		/// 法線
		/// </summary>
		public Vector3 Normal;
		/// <summary>
		/// 定数D
		/// </summary>
		public float D;

		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		/// <param name="d"></param>
		public Plane(float a, float b, float c, float d) {
			Normal = new Vector3(a, b, c); D = d;
		}

		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		public Plane(Vector3 a, Vector3 b, Vector3 c) {
			Vector3 ba, ca;
			Vector3.Subtract(ref b, ref a, out ba);
			Vector3.Subtract(ref c, ref a, out ca);
			Vector3.Cross(ref ba, ref ca, out Normal);
			Vector3.Dot(ref Normal, ref a, out D);
			D = -D;
		}
	}

	public partial struct Plane {
		/// <summary>
		/// 文字列表現を得る。
		/// </summary>
		/// <returns></returns>
		public override string ToString() {
			return string.Format("[{0} : {1} : {2} : {3}]", Normal.X, Normal.Y, Normal.Z, D);
		}
	}

	public partial struct Plane {
		/// <summary>
		/// 法線の正規化。
		/// </summary>
		public void Normalize() {
			Normal.Normalize();
		}
	}

	public partial struct Plane {
		/// <summary>
		/// 法線との内積。
		/// </summary>
		/// <param name="value"></param>
		/// <param name="result"></param>
		public void Dot(ref Vector3 value, out float result) {
			Vector3.Dot(ref Normal, ref value, out result);
		}
		/// <summary>
		/// 法線との内積。
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public float Dot(Vector3 value) {
			float result;
			Dot(ref value, out result);
			return result;
		}
	}

	public partial struct Plane {
		/// <summary>
		/// 法線との内積にDを加算した値。
		/// </summary>
		/// <param name="value"></param>
		/// <param name="result"></param>
		public void DotCoordinate(ref Vector3 value, out float result) {
			Vector3.Dot(ref Normal, ref value, out result);
			result += D;
		}
		/// <summary>
		/// 法線との内積にDを加算した値。
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public float DotCoordinate(Vector3 value) {
			float result;
			DotCoordinate(ref value, out result);
			return result;
		}

		/// <summary>
		/// ３つの平面の交点。
		/// ( a_d(b_n x c_n) + b_d(c_n x a_n) + c_d(a_n x b_n)) : a_n . (b_n x c_n) )
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <param name="c"></param>
		/// <param name="result"></param>
		public static void Intersects(ref Plane a, ref Plane b, ref Plane c, out Vector4 result) {
			Vector3 ab, bc, ca, p;
			float w;
			Vector3.Cross(ref a.Normal, ref b.Normal, out ab);
			Vector3.Cross(ref b.Normal, ref c.Normal, out bc);
			Vector3.Cross(ref c.Normal, ref a.Normal, out ca);
			Vector3.Dot(ref a.Normal, ref bc, out w);
			Vector3.Multiply(ref bc, a.D, out bc);
			Vector3.Multiply(ref ca, b.D, out ca);
			Vector3.Multiply(ref ab, c.D, out ab);
			Vector3.Add(ref bc, ref ca, out p);
			Vector3.Add(ref p, ref ab, out p);
			result = new Vector4(p, w);
		}

	}

}
